﻿using System;
using System.Collections.Generic;
using System.Windows.Media.Media3D;

namespace LxCFD
{
    public class FvZoneBase : MeshSelector, IProvideZoneTopology, IProvideVariableCount, IPrepareMesh
    {
        public Point3DCollection Nodes { get => _nodes; set => _nodes = value; }
        protected Point3DCollection _nodes;
        public FvFace[] Faces;
        public FvCell[] Cells;
        public double Volumn { get; set; }
        public double[] CellCommonArray;
        public double[] FaceCommonArray;
        public IndexNumber InnerIndex { get; set; }
        public IndexNumber TotalIndex { get; set; }
        public AMGInZone AMGSolver { get; set; }
        public BiCGStabInZone BiCGSolver { get; set; }

        public List<FvThread> BoundThreads { get; private set; } = new List<FvThread>();
        public void PrepareMeshData()
        {
            CreatCells();
            CalZoneGeometry();
            CalTotalVolumnArea();
            LxTool.CheckCreateArray(ref CellCommonArray, Cells.Length);
            LxTool.CheckCreateArray(ref FaceCommonArray, Math.Max(Cells.Length, Faces.Length));
        }
        #region 几何模型   
        protected void CreatCells()
        {
            this.Cells = new FvCell[TotalIndex.CellIDs.GetCount()];
            QueueTool oqt = new QueueTool();
            oqt.Create(Cells.Length, Faces.Length);
            QueueTool nqt = new QueueTool();
            nqt.Create(Cells.Length, Faces.Length);
            for (int i1 = 0; i1 < Faces.Length; ++i1)
            {
                ref FvFace f = ref Faces[i1];
                oqt.AddOneToQueue(f.OSideCell, i1);
                nqt.AddOneToQueue(f.NSideCell, i1);
            }
            for (int i1 = 0; i1 < Cells.Length; ++i1)
            {
                ref FvCell c = ref Cells[i1];
                oqt.ConvertQueueToArray(out c.OFaces, i1);
                nqt.ConvertQueueToArray(out c.NFaces, i1);
            }
        }
        protected void CalZoneGeometry()
        {
            int i1 = 0;
            for (; i1 < Faces.Length; i1++)
            {
                Faces[i1].CalGeometryInFace(_nodes);
            }
            i1 = 0;
            for (; i1 <= InnerIndex.CellIDs.End; i1++)
            {
                Cells[i1].CalGeometry_inner(Faces);
            }
            for (; i1 < Cells.Length; i1++)
            {
                Cells[i1].CalGeometry_bound(Faces);
            }
            i1 = 0;
            for (; i1 <= InnerIndex.FaceIDs.End; i1++)
            {
                Faces[i1].CalGeometryAcrossFace_inner(Cells);
            }
            for (; i1 < Faces.Length; i1++)
            {
                ref FvFace face = ref Faces[i1];
                Faces[i1].CalGeometryAcrossFace_bound(Cells);
            }
            i1 = 0;
            for (; i1 < Cells.Length; i1++)
            {
                Cells[i1].CalMatrix_LeastSquare(Faces);
            }
        }
        protected void CalTotalVolumnArea()
        {
            Volumn = 0;
            for (int i1 = InnerIndex.CellIDs.Start; i1 <= InnerIndex.CellIDs.End; i1++)
            {
                Volumn += Cells[i1].Volumn;
            }

            for (int i2 = 0; i2 < BoundThreads.Count; i2++)
            {
                double area = 0;
                var b = BoundThreads[i2];
                for (int i3 = b.ThreadIndex.FaceIDs.Start; i3 <= b.ThreadIndex.FaceIDs.End; i3++)
                {
                    area += Faces[i3].Area;
                }
                b.Area = area;
            }
        }
        public class TempCell
        {
            public List<int> OFaces = new List<int>();
            public List<int> NFaces = new List<int>();
        }

        #endregion
        public int GetVariableCount()
        {
            return Cells.Length;
        }
        //多重网格接口
        int[] IProvideZoneTopology.GetCellOFaces(int CellIndex)
        {
            return Cells[CellIndex].OFaces;
        }

        int[] IProvideZoneTopology.GetCellNFaces(int CellIndex)
        {
            return Cells[CellIndex].NFaces;
        }

        int IProvideZoneTopology.GetFaceOSideCell(int FaceIndex)
        {
            return Faces[FaceIndex].OSideCell;
        }

        int IProvideZoneTopology.GetFaceNSideCell(int FaceIndex)
        {
            return Faces[FaceIndex].NSideCell;
        }

        ONPair IProvideZoneTopology.GetONCellID(int FaceIndex)
        {
            return Faces[FaceIndex].GetONCellID();
        }
        
        //List<IndexNumber> IProvideZoneTopology.GetThreadsIndex()
        //{
        //    List<IndexNumber> l = new List<IndexNumber>();
        //    int threadCount = GetThreadCount();
        //    for(int i1 = 0; i1 < threadCount; i1++)
        //    {
        //        l.Add(GetThread(i1).ThreadIndex);
        //    }
        //    return l;
        //}
        IndexNumber IProvideZoneTopology.GetInnerIndex()
        {
            return InnerIndex;
        }

        IndexNumber IProvideZoneTopology.GetThreadIndex(int threadID)
        {
            return BoundThreads[threadID].ThreadIndex;
        }

        public IndexNumber GetTotalIndex()
        {
            return TotalIndex;
        }

        public int GetThreadCount()
        {
            return BoundThreads.Count;
        }
    }
}
